Conversation
a91c6fd to
9e728fb
Compare
There was a problem hiding this comment.
The changes introduce a comprehensive suite of E2E tests for the treasury module. While the test coverage is good, there are several issues in packages/shared/src/treasury.ts that need attention, including commented-out code, duplicated logic, potentially brittle helpers, unsafe type assertions, and comments indicating some tests are not functional. The new test file for Kusama Asset Hub is well-structured.
Suggestions that couldn't be attached to a specific line
packages/shared/src/treasury.ts:509, 522
The claimTreasurySpend test contains comments (// Not working after moving to asset hub and // assert(dispatchedEvent) not getting the dispatch event...) that indicate the test is broken or incomplete. Incomplete tests should be fixed, marked as .skip, or removed before merging to avoid having non-functional tests in the suite.
packages/shared/src/treasury.ts:370-425, 489-562, 592-666
The test functions voidApprovedTreasurySpendProposal, claimTreasurySpend, and checkStatusOfTreasurySpend contain significant duplicated code for creating and verifying a spend proposal. This setup logic should be extracted into a reusable helper function to reduce code duplication and improve maintainability.
|
|
||
| import { assert, expect } from 'vitest' | ||
|
|
||
| //import { logAllEvents } from './helpers/helper_functions.js' |
There was a problem hiding this comment.
A commented-out import //import { logAllEvents } from './helpers/helper_functions.js' is present. Unused and commented-out code should be removed to improve code clarity.
| const [event] = (await assetHubClient.api.query.system.events()).filter( | ||
| ({ event }: any) => event.section === 'treasury' && event.method === eventType, |
There was a problem hiding this comment.
The getSpendIndexFromEvent helper function filters for an event and directly accesses the first element of the result. This assumes only one event of the specified type will be present in the block's events. This could cause flaky tests if multiple such events are emitted. The function should be made more robust to handle cases where multiple events are found, or it should be documented why only one is expected. Additionally, the event is typed as any, which is not type-safe.
| // const initialSpendCount = await getSpendCount(assetHubClient) | ||
| const initialSpendCount = (await assetHubClient.api.query.treasury.spendCount()).toNumber() |
There was a problem hiding this comment.
There is a commented-out line of code (// const initialSpendCount = ...) which should be removed. Immediately after, the logic from the getSpendCount helper function is duplicated. You should use the existing getSpendCount helper for consistency and to avoid code duplication.
| const pendingOrFailedSpends = spends.filter((spend) => { | ||
| const spendData = spend[1]?.unwrap() | ||
| return ( | ||
| (spendData?.status.isPending || spendData?.status.isFailed) && // not pending or failed |
There was a problem hiding this comment.
The comment // not pending or failed is inconsistent with the code (spendData?.status.isPending || spendData?.status.isFailed). The comment should be corrected to // is pending or failed to accurately reflect the logic.
|
|
||
| // call payout tx for each pending or failed spend | ||
| for (const spend of pendingOrFailedSpends) { | ||
| const spendIndex = spend[0].toHuman?.() as number |
There was a problem hiding this comment.
The code spend[0].toHuman?.() as number is an unsafe way to get the spend index from a StorageKey. toHuman() can return complex objects, and the type assertion as number may fail at runtime. Please use the safer method spend[0].args[0].toNumber() to extract the index.
| // verify the spends status is attempted | ||
| for (const spendIndex of spendIndices) { | ||
| const spend = await assetHubClient.api.query.treasury.spends(spendIndex) | ||
| expect(spend?.unwrap()?.status.isAttempted).toBe(true) |
There was a problem hiding this comment.
The expression spend?.unwrap()?.status.isAttempted can cause a runtime error if spend is None. unwrap() will be called on undefined and throw. You should first assert that the Option is Some before unwrapping it. For example: expect(spend.isSome).toBe(true); expect(spend.unwrap().status.isAttempted).toBe(true);.
|
All tests are passing for KAH locally. |
|
All the tests are now working on the PAH as well locally tested. |
| for (const spendIndex of spendIndices) { | ||
| const checkStatusEvents = await sendCheckStatusTx(assetHubClient, spendIndex) | ||
| await assetHubClient.dev.newBlock() | ||
| await verifyEventSpendProcessed(checkStatusEvents) |
There was a problem hiding this comment.
You might not want this here: from what I can tell, this verifyEventSpendProcessed helper matches against a snapshot; this is being done from within a loop, whose iteration count is unknown.
There could be 1 approved spend in the chain this is running on, or 1000.
For each iteration, a snapshot will be created, which might have already become obsolete by the time the next test run begins.
It is better to just inspect for the presence of the event without snapshotting it.
There was a problem hiding this comment.
Thanks. I got it. I will update it.
There was a problem hiding this comment.
I see you moved these tests to paritytech/ahm-dryrun#261, so this is not urgent.
However, for future reference, checking the same snapshot multiple times in one test is very often unintended.
There was a problem hiding this comment.
Yes, since I have already added the test in the ahm-dryrun repo. I will be removing it from here, as it will be redundant here.
…AssetSpendVoided, sendPayoutTx, verifyEventPaid
…n assethub" This reverts commit f7bb7d5.
…mits `InsufficientPermission` error
1039966 to
befe367
Compare
There was a problem hiding this comment.
The new E2E tests for the treasury module are a valuable addition. However, several areas in the implementation could be improved to make the tests more robust, precise, and less brittle. The feedback focuses on strengthening assertions, improving type safety, and making tests less reliant on potentially fragile implementation details.
| TInitStoragesPara extends Record<string, Record<string, any>> | undefined, | ||
| >(assetHubClient: Client<TCustom, TInitStoragesPara>, eventType: 'AssetSpendApproved' | 'Paid'): Promise<number> { | ||
| const [event] = (await assetHubClient.api.query.system.events()).filter( | ||
| ({ event }: any) => event.section === 'treasury' && event.method === eventType, |
There was a problem hiding this comment.
The use of any for the event record type weakens type safety. Please define or import a proper type for the event record to ensure type checking and improve code clarity.
| TInitStoragesPara extends Record<string, Record<string, any>> | undefined, | ||
| >(assetHubClient: Client<TCustom, TInitStoragesPara>) { | ||
| await checkSystemEvents(assetHubClient, { section: 'treasury', method: 'AssetSpendApproved' }) | ||
| .redact({ redactKeys: /expireAt|validFrom|index|data/ }) |
There was a problem hiding this comment.
Redacting the entire data field in the event snapshot is too broad and may hide potential regressions. It's better to be more specific and only redact fields within data that are non-deterministic (like timestamps or indices), while still capturing the overall structure and values of the event data.
| // ensure that Alice's balance is increased | ||
| const balanceAfter = await assetHubClient.api.query.system.account(testAccounts.alice.address) | ||
| const balanceAmountAfter = balanceAfter.data.free.toBigInt() | ||
| expect(balanceAmountAfter - balanceAmountBefore).toBeGreaterThan(0n) |
There was a problem hiding this comment.
The assertion expect(balanceAmountAfter - balanceAmountBefore).toBeGreaterThan(0n) is too weak. It only confirms that the balance has increased. For a more robust test, please assert that the balance has increased by the spendAmount, potentially accounting for transaction fees if they can be determined or estimated. A more precise check will better validate the payout logic.
| // Ensure that Alice's balance is increased | ||
| const balanceAfter = await assetHubClient.api.query.system.account(testAccounts.alice.address) | ||
| const balanceAmountAfter = balanceAfter.data.free.toBigInt() | ||
| expect(balanceAmountAfter - balanceAmountBefore).toBeGreaterThan(0n) |
There was a problem hiding this comment.
Similar to the comment for line 395, the assertion expect(balanceAmountAfter - balanceAmountBefore).toBeGreaterThan(0n) is not precise enough. The test should verify that the balance increase matches the expected spendAmount to ensure the correct amount was paid out.
|
|
||
| // call payout tx for each pending or failed spend | ||
| for (const spend of pendingOrFailedSpends) { | ||
| const spendIndex = spend[0].toHuman?.() as number |
There was a problem hiding this comment.
Using .toHuman() and casting to number to get the spendIndex is fragile and can break if the human-readable format changes. A more robust way is to get the index directly from the StorageKey arguments, for example: const spendIndex = (spend[0].args[0] as u32).toNumber();. This approach is more resilient to changes in the underlying library.
| // verify the spends status is attempted | ||
| for (const spendIndex of spendIndices) { | ||
| const spend = await assetHubClient.api.query.treasury.spends(spendIndex) | ||
| expect(spend?.unwrap()?.status.isAttempted).toBe(true) |
There was a problem hiding this comment.
The use of optional chaining (spend?.unwrap()?.status.isAttempted) can hide a potential test failure if spend is None. It would be better to first assert that the spend exists (expect(spend.isSome).toBe(true)) and then unwrap it. This makes the test fail explicitly if the spend is unexpectedly missing.
End-to-end tests are added to cover the main flow of Treasury operations
closes Issue #291
WIP